import os, sys, poser, random

os.chdir( os.path.dirname(poser.AppLocation()) )
sys.path.append(os.path.join("Runtime","Python","Poseworks","Particles3","data"))

from prt3Constants import *
from prt3Math import *

def sanitizeName(name):
		import string
		parts = name.split("_")
		if len(parts) > 0:
				name = parts[0]
				suffix = parts[-1].split(":")[0]
		allowed = string.ascii_letters + "-"
		cleaned = ""
		for c in name:
				if allowed.find(c) != -1:
						cleaned = cleaned + c
		return cleaned + "_" + suffix

def createSystem(name, groups, emitter=None):
		system = PwSystem(name)
		for gname, gcount, gshape in groups:
				system.addParticleGroup(gname, gcount, gshape)
		cr2, pp2 = system.write(DIR_TEMP)
		poser.Scene().LoadLibraryFigure(cr2)
		if not emitter:
				poser.Scene().LoadLibraryFigure(pp2)
		else:
				body = poser.Scene().CurrentFigure().ParentActor()
				body.Parameter(PARM_ID).SetValue(emitter)
		system.assignTo(poser.Scene().CurrentFigure(), conformAssigned=True)
		return system

def buildSystemFrom(fig):
		system = PwSystem(fig.Name())
		group = fig.ParentActor()
		particles = group.Children()
		for p in particles:
				if p.IsBodyPart():
						continue
				else:
						particles.remove(p)
		system.addParticleGroup(group.Name(), len(particles), group.Parameter(PARM_SHAPE).Value())
		system.assignTo(fig)
		return system

class PwMover(object):
		def __init__(self, move=PwVector(0,0,0), accel=PwVector(0,0,0), var=0):
				self.movement = move
				self.acceleration = accel
				self.variance = var
		def __mul__(self, other):
				self.movement = self.movement * other
				self.acceleration = self.acceleration * other
				return self
		def setMovement(self, vector):
				self.movement = vector
		def setAcceleration(self, vector):
				self.acceleration = vector
		def setVariance(self, v):
				import random
				self.variance = v
				var = (random.random() - 0.5) * (v / 2)
				self.movement.x = self.movement.x + var
				self.movement.y = self.movement.y + var
				self.movement.z = self.movement.z + var
		def define(self, move, accel, var):
				self.setMovement(move)
				self.setAcceleration(accel)
				self.setVariance(var)
		def get(self, life):
				x = life * self.movement.x * (1.0 + self.acceleration.x) ** life
				y = life * self.movement.y * (1.0 + self.acceleration.y) ** life
				z = life * self.movement.z * (1.0 + self.acceleration.z) ** life
				return PwVector(x, y, z)
		def getUnmultiplied(self, life):
				x = self.movement.x * (1.0 + self.acceleration.x) ** life
				y = self.movement.y * (1.0 + self.acceleration.y) ** life
				z = self.movement.z * (1.0 + self.acceleration.z) ** life
				return PwVector(x, y, z)

class PwPoserObject(object):
		def __init__(self):
				pass
				self.source = None
		def assignTo(self, obj):
				self.source = obj
		def getObject(self):
				return self.source
		def Name(self):
				return self.source.Name()

class PwPoserParameters(object):
		def __init__(self, owner, actor):
				for iname in owner.channels:
						channel = owner.getChannel(iname)
						self.__setattr__(channel.iname, actor.Parameter(channel.name))
				self.xtran = actor.ParameterByCode(poser.kParmCodeXTRAN)
				self.ytran = actor.ParameterByCode(poser.kParmCodeYTRAN)
				self.ztran = actor.ParameterByCode(poser.kParmCodeZTRAN)
				self.xrot = actor.ParameterByCode(poser.kParmCodeXROT)
				self.yrot = actor.ParameterByCode(poser.kParmCodeYROT)
				self.zrot = actor.ParameterByCode(poser.kParmCodeZROT)
				self.scale = actor.ParameterByCode(poser.kParmCodeASCALE)
				self.xscale = actor.ParameterByCode(poser.kParmCodeXSCALE)
				self.yscale = actor.ParameterByCode(poser.kParmCodeYSCALE)
				self.zscale = actor.ParameterByCode(poser.kParmCodeZSCALE)
		def setTran(self, x, y, z):
				for parm, v in [("xtran", x), ("ytran", y), ("ztran", z)]:
						self.key(parm, v)
		def getTran(self):
				return PwPoint( self.get("xtran"), self.get("ytran"), self.get("ztran") )
		def setRot(self, x, y, z):
				for parm, v in [("xrot", x), ("yrot", y), ("zrot", z)]:
						self.key(parm, v)
		def getRot(self):
				return PwVector( self.get("xrot"), self.get("yrot"), self.get("zrot") )
		def setScale(self, a, x, y, z):
				for parm, v in [("scale", a), ("xscale", x), ("yscale", y), ("zscale", z)]:
						self.key(parm, v)
		def getScale(self):
				return (self.get("scale"), self.get("xscale"), self.get("yscale"), self.get("zscale"))
		def setRateOfEmission(self, v):
				self.key(IPARM_EMISSION, v)
		def getRateOfEmission(self):
				return self.get(IPARM_EMISSION)
		def setEmissionAngle(self, v):
				self.key(IPARM_EMISSIONANGLE, v)
		def getEmissionAngle(self):
				return self.get(IPARM_EMISSIONANGLE)
		def setRecycle(self, v):
				self.key(IPARM_RECYCLE, ifelse(v, 1.0, 0))
		def getRecycle(self):
				return ifelse(self.get(IPARM_RECYCLE), 1.0, 0)
		def setLifespan(self, v):
				self.key(IPARM_LIFESPAN, v)
		def getLifespan(self):
				return self.get(IPARM_LIFESPAN)
		def setStart(self, v):
				self.key(IPARM_START, v)
		def getStart(self):
				return self.get(IPARM_START)
		def setEnd(self, v):
				self.key(IPARM_END, v)
		def getEnd(self):
				return self.get(IPARM_END)
		def setGravity(self, v):
				self.key(IPARM_GRAVITY, v * 100)
		def getGravity(self):
				return self.get(IPARM_GRAVITY)/100
		def setAttraction(self, v):
				self.key(IPARM_ATTRACTION, v)
		def getAttraction(self):
				return self.get(IPARM_ATTRACTION)
		def setDampening(self, v):
				self.key(IPARM_DAMPENING, v)
		def getDampening(self):
				return self.get(IPARM_DAMPENING)
		def setVelocity(self, x, y, z):
				for parm, v in [(IPARM_VELOCITYX, x), (IPARM_VELOCITYY, y), (IPARM_VELOCITYZ, z)]:
						self.key(parm, v)
		def getVelocity(self):
				return PwVector(self.get(IPARM_VELOCITYX), self.get(IPARM_VELOCITYY), self.get(IPARM_VELOCITYZ))
		def setAcceleration(self, x, y, z):
				for parm, v in [(IPARM_ACCELERATIONX, x), (IPARM_ACCELERATIONY, y), (IPARM_ACCELERATIONZ, z)]:
						self.key(parm, v)
		def getAcceleration(self):
				return PwVector(self.get(IPARM_ACCELERATIONX),self.get(IPARM_ACCELERATIONY), self.get(IPARM_ACCELERATIONZ))
		def setVelocityVariance(self, v):
				self.key(IPARM_VELOCITYVAR, v)
		def getVelocityVariance(self):
				return self.get(IPARM_VELOCITYVAR)
		def setOrbit(self, x, y, z):
				for parm, v in [(IPARM_ORBITX, x), (IPARM_ORBITY, y), (IPARM_ORBITZ, z)]:
						self.key(parm, v)
		def getOrbit(self):
				return PwVector(self.get(IPARM_ORBITX), self.get(IPARM_ORBITY), self.get(IPARM_ORBITZ))
		def setOrbitAcceleration(self, x, y, z):
				for parm, v in [(IPARM_ORBITAX, x), (IPARM_ORBITAY, y), (IPARM_ORBITAZ, z)]:
						self.key(parm, v)
		def getOrbitAcceleration(self):
				return PwVector(self.get(IPARM_ORBITAX), self.get(IPARM_ORBITAY), self.get(IPARM_ORBITAZ))
		def setOrbitVariance(self, v):
				self.key(IPARM_ORBITVAR, v)
		def getOrbitVariance(self):
				return self.get(IPARM_ORBITVAR)
		def setSpin(self, x, y, z):
				for parm, v in [(IPARM_SPINX, x), (IPARM_SPINY, y), (IPARM_SPINZ, z)]:
						self.key(parm, v)
		def getSpin(self):
				return PwVector(self.get(IPARM_SPINX), self.get(IPARM_SPINY), self.get(IPARM_SPINZ))
		def setSpinAcceleration(self, x, y, z):
				for parm, v in [(IPARM_SPINAX, x), (IPARM_SPINAY, y), (IPARM_SPINAZ, z)]:
						self.key(parm, v)
		def getSpinAcceleration(self):
				return PwVector(self.get(IPARM_SPINAX), self.get(IPARM_SPINAY), self.get(IPARM_SPINAZ))
		def setSpinVariance(self, v):
				self.key(IPARM_SPINVAR, v)
		def getSpinVariance(self):
				return self.get(IPARM_SPINVAR)
		def setGrow(self, x, y, z):
				for parm, v in [(IPARM_GROWX, x), (IPARM_GROWY, y), (IPARM_GROWZ, z)]:
						self.key(parm, v*100)
		def getGrow(self):
				return PwVector(self.get(IPARM_GROWX)/100, self.get(IPARM_GROWY)/100, self.get(IPARM_GROWZ)/100)
		def setGrowAcceleration(self, x, y, z):
				for parm, v in [(IPARM_GROWAX, x), (IPARM_GROWAY, y), (IPARM_GROWAZ, z)]:
						self.key(parm, v*100)
		def getGrowAcceleration(self):
				return PwVector(self.get(IPARM_GROWAX)/100, self.get(IPARM_GROWAY)/100, self.get(IPARM_GROWAZ)/100)
		def setGrowVariance(self, v):
				self.key(IPARM_GROWVAR, v)
		def getGrowVariance(self):
				return self.get(IPARM_GROWVAR)/100
		def setLife(self, v):
				self.key(IPARM_LIFE, v)
		def getLife(self):
				return self.get(IPARM_LIFE)
		def setSpawnPoint(self, x, y, z):
				for parm, v in [(IPARM_SPAWNPNTX, x), (IPARM_SPAWNPNTY, y), (IPARM_SPAWNPNTZ, z)]:
						self.key(parm, v)
		def getSpawnPoint(self):
				return PwPoint( self.get(IPARM_SPAWNPNTX), self.get(IPARM_SPAWNPNTY), self.get(IPARM_SPAWNPNTZ) )
		def setSpawnVector(self, x, y, z):
				for parm, v in [(IPARM_SPAWNVECX, x), (IPARM_SPAWNVECY, y), (IPARM_SPAWNVECZ, z)]:
						self.key(parm, v)
		def getSpawnVector(self):
				return PwVector( self.get(IPARM_SPAWNVECX), self.get(IPARM_SPAWNVECY), self.get(IPARM_SPAWNVECZ) )
		def setScaleMod(self, x, y, z):
				for parm, v in [(IPARM_XSCALEMOD, x), (IPARM_YSCALEMOD, y), (IPARM_ZSCALEMOD, z)]:
						self.key(parm, v)
		def getScaleMod(self):
				return PwVector( self.get(IPARM_XSCALEMOD), self.get(IPARM_YSCALEMOD), self.get(IPARM_ZSCALEMOD) )
		def setType(self, v):
				self.key(IPARM_TYPE, v)
		def getType(self):
				return self.get(IPARM_TYPE)
		def setShape(self, v):
				self.key(IPARM_SHAPE, v)
		def getShape(self):
				return self.get(IPARM_SHAPE)
		def setCount(self, v):
				self.key(IPARM_COUNT, v)
		def getCount(self):
				return self.get(IPARM_COUNT)
		def getParticleOffset(self):
				return PwPoint( self.get(IPARM_PXTRAN), self.get(IPARM_PYTRAN), self.get(IPARM_PZTRAN) )
		def getParticleScale(self):
				return self.get(IPARM_PSCALE)/100, self.get(IPARM_PXSCALE)/100, self.get(IPARM_PYSCALE)/100, self.get(IPARM_PXSCALE)/100
		def get(self, parm):
				return self.__getattribute__(parm).Value()
		def key(self, parm, v):
				self.__getattribute__(parm).SetValue(v)
				self.__getattribute__(parm).AddKeyFrame()
		
class PwPoserActor(PwPoserObject):
		def __init__(self):
				PwPoserObject.__init__(self)
				self.channels = []
		def assignTo(self, obj, conformAssigned=False):
				PwPoserObject.assignTo(self, obj)
				self.parameters = PwPoserParameters(self, obj)
				if conformAssigned:
						self.conform(self.source)
		def setType(self, kind):
				self.setChannel(IPARM_TYPE, kind)
		def addChannel( self, iname, name, value, hidden=False, kind="valueParm" ):
				self.__setattr__( iname, PwParameter( kind, iname, name, value, hidden ) )
				self.channels.append( iname )
		def getChannel( self, iname ):
				return self.__getattribute__( iname )
		def setChannel( self, iname, v ):
				self.__getattribute__(iname).value = v
		def getObjectSpace(self):
				tup = self.source.WorldMatrix()
				matrix = PwMatrix()
				for row in tup:
						newrow = []
						for col in row:
								newrow.append(col)
						matrix.append(newrow)
				return matrix.transpose()
		def getObjectRotation(self):
				return PwQuaternion(self.source.WorldQuaternion()).euler()

class PwERC(object):
		def __init__(self, figure, group, channel, ratio):
				self.figure = figure
				self.group = group
				self.channel = channel
				self.ratio = ratio
		def write(self):
				return "\n\t\t\tvalueOpDeltaAdd" +\
					   "\n\t\t\t\t%s" % self.figure +\
					   "\n\t\t\t\t%s" % self.group +\
					   "\n\t\t\t\t%s" % self.channel +\
					   "\n\t\t\tdeltaAddDelta %f" % self.ratio

class PwParameter(PwPoserObject):
		def __init__(self, kind, iname, name, value, hidden):
				self.kind = kind
				self.iname = iname
				self.name = name
				self.value = value
				self.hidden = hidden
				self.links = []
		def addLink(self, figure, group, channel, ratio):
				self.links.append( PwERC(figure, group, channel, ratio) )
		def write(self):
				links = ""
				for link in self.links:
						links = links + link.write()
				return "\n\t\t%s %s" % (self.kind, self.iname) +\
					   "\n\t\t\t{" +\
					   "\n\t\t\tname %s" % self.name +\
					   "\n\t\t\tinitValue %f" % self.value +\
					   "\n\t\t\thidden %i" % self.hidden +\
					   "\n\t\t\tkeys" +\
					   "\n\t\t\t\t{" +\
					   "\n\t\t\t\tstatic 0" +\
					   "\n\t\t\t\tk 0 %f" % self.value +\
					   "\n\t\t\t\t}" +\
					   links +\
					   "\n\t\t\t}"

class PwMaterial(PwPoserObject):
		def __init__(self, sName, tKd, tKa):
				self.name = sName
				self.kd = tKd
				self.ka = tKa
		def write(self):
				return "\n\tmaterial %s" % self.name +\
					   "\n\t\t{" +\
					   "\n\t\tKdColor %f %f %f %f" % self.kd +\
					   "\n\t\tKaColor %f %f %f %f" % self.ka +\
					   "\n\t\tKsColor 0 0 0 1" +\
					   "\n\t\t}"

class PwElement(PwPoserActor):
		def __init__(self, oParent, sName):
				PwPoserActor.__init__(self)
				self.prop = False
				self.name = sName
				self.iname = sanitizeName(sName)
				self.geom = ""
				self.on = "on"
				self.bend = 0
				self.dynamicsLock = 1
				self.hidden = 0
				self.addToMenu = 1
				self.castsShadow = 0
				self.includeInDepthCue = 1
				self.parent = oParent
				self.groups = []
				self.addGroup( "Transform", ["scale", "xScale", "yScale", "zScale", "rotateX", "rotateY", "rotateZ", "translateX", "translateY", "translateZ"] )
				self.addChannel( IPARM_TYPE, PARM_TYPE, 0.0, hidden=True )
				self.addChannel( "originX", "GetStringRes(1028,44)", 0.0, kind="xOffsetA", hidden=True )
				self.addChannel( "originY", "GetStringRes(1028,45)", 0.0, kind="yOffsetA", hidden=True )
				self.addChannel( "originZ", "GetStringRes(1028,46)", 0.0, kind="zOffsetA", hidden=True )
				self.addChannel( "xOffB", "xOffB", 0.0, kind="xOffsetB", hidden=True )
				self.addChannel( "yOffB", "yOffB", 0.0, kind="yOffsetB", hidden=True )
				self.addChannel( "zOffB", "zOffB", 0.001, kind="zOffsetB", hidden=True )
				self.origin = (0.0, 0.0, 0)
				self.endPoint = (0.0, 0.0, 1)
				self.orientation = (0.0, 0.0, 0.0)
				self.displayOrigin = 0
				self.displayMode = "USEPARENT"
				self.customMaterial = 0
				self.materials = []
				self.addMaterial("Preview", (1,1,1,1), (0,0,0,1))
				self.locked = 0
				self.visibleInRender = 1
		def addTranslations( self, hidden=False ):
				self.addChannel( "xtran", "GetStringRes(1028,12)", 0.0, kind="translateX", hidden=hidden )
				self.addChannel( "ytran", "GetStringRes(1028,13)", 0.0, kind="translateY", hidden=hidden )
				self.addChannel( "ztran", "GetStringRes(1028,14)", 0.0, kind="translateZ", hidden=hidden )
		def addRotations( self, hidden=False ):
				self.addChannel( "xRotate", "xrot", 0.0, kind="rotateX", hidden=hidden )
				self.addChannel( "yRotate", "yrot", 0.0, kind="rotateY", hidden=hidden )
				self.addChannel( "zRotate", "zrot", 0.0, kind="rotateZ", hidden=hidden )
		def addScales( self, hidden=False ):
				self.addChannel( "scale", "GetStringRes(1028,5)", 1.0, kind="propagatingScale", hidden=hidden )
				self.addChannel( "xScale", "GetStringRes(1028,6)", 1.0, kind="propagatingScaleX", hidden=hidden )
				self.addChannel( "yScale", "GetStringRes(1028,7)", 1.0, kind="propagatingScaleY", hidden=hidden )
				self.addChannel( "zScale", "GetStringRes(1028,8)", 1.0, kind="propagatingScaleZ", hidden=hidden )
		def addControlToScales(self, figure, group, aScaleCtrl, xScaleCtrl, yScaleCtrl, zScaleCtrl, ratio):
				"""
				for parm, ctrl in [(self.xScale, xScaleCtrl),
								   (self.yScale, yScaleCtrl),
								   (self.zScale, zScaleCtrl)]:
						parm.addLink( figure, group, ctrl, ratio )
				"""
				for parm in [self.xScale, self.yScale, self.zScale]:
						parm.addLink( figure, group, aScaleCtrl, ratio )
		def addModifierToScales(self, figure, group, xScaleMod, yScaleMod, zScaleMod, ratio):
				for parm, ctrl in [(self.xScale, xScaleMod), (self.yScale, yScaleMod), (self.zScale, zScaleMod)]:
						parm.addLink( figure, group, ctrl, ratio )
		def addControlToRots(self, figure, group, xRotCtrl, yRotCtrl, zRotCtrl, ratio):
				for parm, ctrl in [(self.xRotate, xRotCtrl),
								   (self.yRotate, yRotCtrl),
								   (self.zRotate, zRotCtrl)]:
						parm.addLink( figure, group, ctrl, ratio )
		def addControlToTrans(self, figure, group, xTranCtrl, yTranCtrl, zTranCtrl, ratio):
				for parm, ctrl in [(self.xtran, xTranCtrl),
								   (self.ytran, yTranCtrl),
								   (self.ztran, zTranCtrl)]:
						parm.addLink( figure, group, ctrl, ratio )
		def addGroup( self, name, channels ):
				self.groups.append( [name, channels] )
		def setGeometry( self, geompath ):
				self.geom = geompath
		def addMaterial(self, material, kd, ka):
				self.materials.append( PwMaterial(material, kd, ka) )
		def writeGeometry( self ):
				if self.geom:
						geomline = "\tstorageOffset 0 0 0\n\tobjFileGeom 0 0 %s" % self.geom
				else:
						geomline = ""
				return "\n%s %s%s\n\t{\n%s\n\t}" % (ifelse(self.prop, "prop", "actor"), self.iname, ifelse(self.prop, "", ":1"), geomline)
		def writeActor( self ):
				channels = "\t\tgroups\n\t\t\t{"
				for group, parms in self.groups:
						channels = channels + "\n\t\t\tgroupNode %s\n\t\t\t\t{" % group
						for parm in parms:
								channels = channels + "\n\t\t\t\tparmNode %s" % parm
						channels = channels + "\n\t\t\t\t}"
				channels = channels + "\n\t\t\t}"
				for channel in self.channels:
						channels = channels + self.__getattribute__(channel).write()
				materials = self.writeMaterials()
				return "\n%s %s%s" % (ifelse(self.prop, "prop", "actor"), self.iname, ifelse(self.prop, "", ":1")) +\
						"\n\t{" +\
						"\n\tname %s" % self.name +\
						"\n\t%s" % self.on +\
						"\n\tbend %i" % self.bend +\
						"\n\tdynamicsLock %i" % self.dynamicsLock +\
						"\n\thidden %i" % self.hidden +\
						"\n\taddToMenu %i" % self.addToMenu +\
						"\n\tcastsShadow %i" % self.castsShadow +\
						"\n\tincludeInDepthCue %i" % self.includeInDepthCue +\
						"\n\tparent %s%s" % (self.parent.iname, ifelse(self.parent.prop, "", ":1")) +\
						"\n\tchannels" +\
						"\n\t\t{" +\
						"\n%s" % channels +\
						"\n\t\t}" +\
						"\n\tendPoint %f %f %f" % self.endPoint +\
						"\n\torigin %f %f %f" % self.origin +\
						"\n\torientation %i %i %i" % self.orientation +\
						"\n\tdisplayOrigin %i" % self.displayOrigin +\
						"\n\tdisplayMode %s" % self.displayMode +\
						"\n\tcustomMaterial %i" % self.customMaterial +\
						materials +\
						"\n\tlocked %s" % self.locked +\
						"\n\tvisibleInRender %i" % self.visibleInRender +\
						"\n\t}"
		def writeAddChild(self):
				return "\n\taddChild %s%s" % (self.iname, ifelse(self.prop,"",":1")) +\
					   "\n\t\t%s%s" % (self.parent.iname, ifelse(self.parent.prop, "", ":1") )
		def writeRoot(self):
				return "\n\troot %s%s" % (self.iname, ifelse(self.prop,"",":1"))
		def writeMaterials(self):
				materials = ""
				for m in self.materials:
						materials = materials + m.write()
				return materials

UNIVERSE = PwElement(None, "UNIVERSE")

class PwSystem(PwPoserActor):
		def __init__(self, sName):
				PwPoserActor.__init__(self)
				self.name = sName
				self.iname = sanitizeName(sName)
				import random
				self.id = float( int(random.random() * 1000000) )
				self.particlegroups = []
				self.emitter = PwEmitter(self)
				self.resFile = ""
		def assignTo(self, fig, conformAssigned=True):
				PwPoserObject.assignTo(self, fig)
				body = self.particlegroups[0]
				body.assignTo(fig.ParentActor())
				#body.parameters.get(PARM_ID)
				for p in body.particles:
						p.assignTo(fig.Actor(p.name))
				# Synch emitter with system
				self.emitter.id = self.id
				self.id = fig.ParentActor().Parameter(PARM_ID).Value()
				for prop in poser.Scene().Actors():
						if prop.IsProp():
								parm = prop.Parameter(PARM_ID)
								if parm and parm.Value() == self.id:
										self.emitter.assignTo(prop)
										break
				if not self.emitter.source:
					poser.DialogSimple.MessageBox("No emitter was found in the scene for " + self.name)
					raise self.name + " is missing its emitter prop."
				if conformAssigned:
						body.parameters.setShape(body.shape)
						body.parameters.setCount(body.numParticles())
		def addParticleGroup(self, sName, nParticles, nShape):
				oGroup = PwParticleGroup( self, sName, nParticles, nShape )
				self.particlegroups.append( oGroup )
		def numGroups( self ):
				return len( self.particlegroups )
		def write(self, outdir):
				outcr2 = os.path.join(outdir, "temp.cr2")
				outpp2 = os.path.join(outdir, "temp.pp2")
				geoms = ""
				actors = ""
				groupedChildren = ""
				figureMaterials = ""
				for g in self.particlegroups:
						geoms = geoms + g.writeGeometry()
						actors = actors + g.writeActor()
						groupedChildren = groupedChildren + g.writeRoot()
						figureMaterials = g.writeMaterials()
						for p in g.particles:
								geoms = geoms + p.writeGeometry()
								actors = actors + p.writeActor()
								groupedChildren = groupedChildren + p.writeAddChild()
				out =  "{" +\
					   "\nversion" +\
					   "\n\t{" +\
					   "\n\tnumber 6.0" +\
					   "\n\t}" +\
					   "\nfigureResFile \"%s\"" % self.resFile +\
					   geoms +\
					   "\nfigureResFile \"%s\"\n" % self.resFile +\
					   actors +\
					   "\n\nfigure" +\
					   "\n\t{" +\
					   "\n\tname %s" % self.name +\
					   groupedChildren +\
					   "\n\tdefaultPick BODY:1" +\
					   "\n\tdisplayOn 1" +\
					   "\n\tallowsBending 0" +\
					   "\n\tfigureType 1318" +\
					   "\n\torigFigureType 1318" +\
					   "\n\tcanonType 8" +\
					   "\n\tconforming 0" +\
					   figureMaterials +\
					   "\n\tdisplayMode USEPARENT" +\
					   "\n\tlocked 0" +\
					   "\n\t}" +\
					   "\n\tsetGeomHandlerOffset 0 0 0" +\
					   "\n}"
				f = open(outcr2, "w")
				f.write(out)
				f.close()
				out = "{" +\
					  "\nversion" +\
					  "\n\t{" +\
					  "\n\tnumber 6.0" +\
					  "\n\t}" +\
					  self.emitter.writeGeometry() +\
					  self.emitter.writeActor() +\
					  "\n\ndoc" +\
					  "\n\t{" +\
					  "\n\taddActor %s" % self.emitter.iname +\
					  "\n\t}"
				f = open(outpp2, "w")
				f.write(out)
				f.close()
				return outcr2, outpp2

class PwEmitter(PwElement):
		def __init__(self, oParent):
				PwElement.__init__(self, oParent, oParent.name + " Emitter")
				self.setType(EMITTER_TYPE)
				self.parent = UNIVERSE
				self.system = oParent
				self.iname = sanitizeName(self.system.name) + "Emitter"
				self.geom = GEOM_EMITTER
				self.addScales(hidden=True)
				self.addRotations()
				self.addTranslations()
				self.addGroup( "Simulation", [IPARM_EMISSIONANGLE] )
				self.addChannel( IPARM_EMISSIONANGLE, PARM_EMISSIONANGLE, 60.0 )
				self.addChannel( IPARM_ID, PARM_ID, self.system.id )
				self.customMaterial = 1
				self.addMaterial( "ArrowX", (1,0,0,0.5), (1,0,0,0.5) )
				self.addMaterial( "ArrowY", (0,1,0,0.5), (0,1,0,0.5) )
				self.addMaterial( "ArrowZ", (0,0,1,0.5), (0,0,1,0.5) )
				self.addMaterial( "EmitterBase", (1,1,1,0.5), (1,1,1,0.5) )
				self.prop = True
				self.visibleInRender = 0
		def getSpawnPoint(self):
				return PwPoint( self.source.WorldDisplacement() )
		def getSpawnRotation(self):
				if self.source:
						def getVectorRotation(obj):
								rotation = PwVector(0,0,0)
								parm = obj.ParameterByCode(poser.kParmCodeXROT)
								if parm: rotation.x = parm.Value()
								parm = obj.ParameterByCode(poser.kParmCodeYROT)
								if parm: rotation.y = parm.Value()
								parm = obj.ParameterByCode(poser.kParmCodeZROT)
								if parm: rotation.z = parm.Value()
								parent = obj.Parent()
								if parent and parent.InternalName() != "UNIVERSE":
										rotation += getVectorRotation(parent)
								return rotation
						rotation = getVectorRotation(self.source)
						return rotation
				return None
		def getSpawnVector(self):
				x_angle = self.parameters.getEmissionAngle()/2 * ifelse(random.random() >= 0.5, 1.0, -1.0) * random.random()
				y_angle = random.random()*360
				x_rot = rotation(XAXIS, x_angle)
				y_rot = rotation(YAXIS, y_angle)
				vector = PwQuaternion(self.source.WorldQuaternion()).matrix() * (y_rot * x_rot * YAXIS)
				#vector = PwQuaternion(self.source.WorldQuaternion()) * (y_rot * x_rot * YAXIS)
				return y_rot, x_rot, PwVector(x_angle, y_angle, 0), vector

class PwParticle(PwElement):
		def __init__(self, oParent, sName):
				PwElement.__init__(self, oParent, sName)
				self.setType(PARTICLE_TYPE)
				self.addScales(hidden=True)
				self.addRotations(hidden=True)
				self.addTranslations(hidden=True)
				self.addChannel( IPARM_LIFE, PARM_LIFE, 0.0, hidden=True )
				self.customMaterial = 1
				self.kill()
		def addScales(self, hidden=False):
				PwElement.addScales(self, hidden=hidden)
				self.scale.value = 0.0
		def spawn(self, emitter, group):
				#self.localPoint = group.parameters.getParticleOffset() # PwPoint(0,0,0)
				self.localRotation = PwVector(0,0,0)
				self.localScale = PwVector(0,0,0)
				self.spawnPoint = emitter.getSpawnPoint()
				self.spawnYrot, self.spawnXrot, self.spawnAngle, self.spawnVector = emitter.getSpawnVector()
				self.spawnSpace = emitter.getObjectSpace()
				#* translation(self.spawnPoint.x,
				#							   self.spawnPoint.y,
				#							   self.spawnPoint.z)
				##self.spawnSpace = self.spawnYrot * self.spawnXrot * emitter.getObjectSpace()
				###self.spawnSpace = emitter.getObjectSpace() * self.spawnYrot * self.spawnXrot
				self.localPoint = self.spawnYrot * self.spawnXrot * group.parameters.getParticleOffset() # PwPoint(0,0,0)
				###self.localPoint = group.parameters.getParticleOffset()
				#self.spawnRotation = emitter.getSpawnRotation() #emitter.getObjectRotation()
				"""
				self.spawnYrot = rotation(YAXIS, 0)
				self.spawnXrot = rotation(XAXIS, 0)
				self.spawnAngle = PwVector(0,1,0)
				"""
				self.spawnVector = PwQuaternion(emitter.source.WorldQuaternion()).matrix() * PwVector(0,1,0)
				#self.spawnVector = PwQuaternion(emitter.source.WorldQuaternion()) * PwVector(0,1,0)
				self.spawnRotation = emitter.getObjectRotation()
				self.velocity.define( group.parameters.getVelocity(),
									  group.parameters.getAcceleration(),
									  group.parameters.getVelocityVariance() )
				#self.velocity.define( group.parameters.getVelocity()/poser.Scene().FramesPerSecond(),
				#					   group.parameters.getAcceleration(),
				#					   group.parameters.getVelocityVariance() )
				self.orbit.define( group.parameters.getOrbit(),
								   group.parameters.getOrbitAcceleration(),
								   group.parameters.getOrbitVariance() )
				self.spin.define( group.parameters.getSpin(),
								  group.parameters.getSpinAcceleration(),
								  group.parameters.getSpinVariance() )
				self.grow.define( group.parameters.getGrow(),
								  group.parameters.getGrowAcceleration(),
								  group.parameters.getGrowVariance() )
				self.parameters.setLife(1.0)
				self.parameters.setScale(1.0, 0.0, 0.0, 0.0)
		def kill(self):
				self.spawnPoint = None
				self.spawnVector = None
				self.spawnSpace = None
				self.velocity = PwMover()
				self.orbit = PwMover()
				self.spin = PwMover()
				self.grow = PwMover()
				if self.source:
						self.parameters.setLife(-1.0)
						self.parameters.setScale(0.0, 0.0, 0.0, 0.0)
						self.parameters.setRot(0.0, 0.0, 0.0)
						self.parameters.setTran(0.0,0.0,0.0)
		def key(self):
				self.source.AddKeyFrame()
		def unkey(self, frame):
				self.source.DeleteKeyFrame(int(frame))

class PwParticleGroup(PwElement):
		def __init__(self, oParent, sName, nParticles, nShape):
				PwElement.__init__(self, oParent, sName)
				self.setType(GROUP_TYPE)
				self.system = oParent
				self.parent = UNIVERSE
				self.name = "GetStringRes(1024,1)"
				self.iname = "BODY"
				self.on = "off"
				#self.addScales()
				#self.addRotations()
				#self.addTranslations()
				self.addChannel( IPARM_ID, PARM_ID, oParent.id )
				self.particles = []
				self.addScales(hidden=True)
				self.addRotations(hidden=True)
				self.addTranslations(hidden=True)
				self.addGroup( "Particle Transform", [IPARM_PSCALE, IPARM_PXSCALE, IPARM_PYSCALE, IPARM_PZSCALE, IPARM_PXROTATE, IPARM_PYROTATE, IPARM_PZROTATE, IPARM_PXTRAN, IPARM_PYTRAN, IPARM_PZTRAN] )
				self.addGroup( "Simulation", [IPARM_EMISSION, IPARM_RECYCLE, IPARM_LIFESPAN, IPARM_START, IPARM_END, IPARM_GRAVITY] )
				self.addGroup( "Velocity", [IPARM_VELOCITYX, IPARM_VELOCITYY, IPARM_VELOCITYZ, IPARM_ACCELERATIONX, IPARM_ACCELERATIONY, IPARM_ACCELERATIONZ, IPARM_VELOCITYVAR] )
				self.addGroup( "Orbit", [IPARM_ORBITX, IPARM_ORBITY, IPARM_ORBITZ, IPARM_ORBITAX, IPARM_ORBITAY, IPARM_ORBITAZ, IPARM_ORBITVAR] )
				self.addGroup( "Spin", [IPARM_SPINX, IPARM_SPINY, IPARM_SPINZ, IPARM_SPINAX, IPARM_SPINAY, IPARM_SPINAZ, IPARM_SPINVAR] )
				self.addGroup( "Grow", [IPARM_GROWX, IPARM_GROWY, IPARM_GROWZ, IPARM_GROWAX, IPARM_GROWAY, IPARM_GROWAZ, IPARM_GROWVAR] )
				self.addChannel( IPARM_COUNT, PARM_COUNT, nParticles, hidden=True )
				self.addChannel( IPARM_SHAPE, PARM_SHAPE, 0.0, hidden=True )
				# Particle Transform
				self.addChannel( IPARM_PSCALE, PARM_PSCALE, 100.0 )
				#self.addChannel( IPARM_PXSCALE, PARM_PXSCALE, 100.0 )
				#self.addChannel( IPARM_PYSCALE, PARM_PYSCALE, 100.0 )
				#self.addChannel( IPARM_PZSCALE, PARM_PZSCALE, 100.0 )
				self.addChannel( IPARM_PXROTATE, PARM_PXROTATE, 0.0 )
				self.addChannel( IPARM_PYROTATE, PARM_PYROTATE, 0.0 )
				self.addChannel( IPARM_PZROTATE, PARM_PZROTATE, 0.0 )
				self.addChannel( IPARM_PXTRAN, PARM_PXTRAN, 0.0 )
				self.addChannel( IPARM_PYTRAN, PARM_PYTRAN, 0.0 )
				self.addChannel( IPARM_PZTRAN, PARM_PZTRAN, 0.0 )
				# Simulation
				self.addChannel( IPARM_EMISSION, PARM_EMISSION, 1.0 )
				self.addChannel( IPARM_RECYCLE, PARM_RECYCLE, 1.0 )
				self.addChannel( IPARM_LIFESPAN, PARM_LIFESPAN, 30.0 )
				self.addChannel( IPARM_START, PARM_START, 1.0 )
				self.addChannel( IPARM_END, PARM_END, -1.0 )
				self.addChannel( IPARM_GRAVITY, PARM_GRAVITY, 1.0 )
				# Velocity
				self.addChannel( IPARM_VELOCITYX, PARM_VELOCITYX, 0.0 )
				self.addChannel( IPARM_VELOCITYY, PARM_VELOCITYY, 1.0 )
				self.addChannel( IPARM_VELOCITYZ, PARM_VELOCITYZ, 0.0 )
				self.addChannel( IPARM_ACCELERATIONX, PARM_ACCELERATIONX, 0.0 )
				self.addChannel( IPARM_ACCELERATIONY, PARM_ACCELERATIONY, -0.1 )
				self.addChannel( IPARM_ACCELERATIONZ, PARM_ACCELERATIONZ, 0.0 )
				self.addChannel( IPARM_VELOCITYVAR, PARM_VELOCITYVAR, 0.0 )
				# Orbit
				self.addChannel( IPARM_ORBITX, PARM_ORBITX, 0.0 )
				self.addChannel( IPARM_ORBITY, PARM_ORBITY, 0.0 )
				self.addChannel( IPARM_ORBITZ, PARM_ORBITZ, 0.0 )
				self.addChannel( IPARM_ORBITAX, PARM_ORBITAX, 0.0 )
				self.addChannel( IPARM_ORBITAY, PARM_ORBITAY, 0.0 )
				self.addChannel( IPARM_ORBITAZ, PARM_ORBITAZ, 0.0 )
				self.addChannel( IPARM_ORBITVAR, PARM_ORBITVAR, 0.0 )
				# Spin
				self.addChannel( IPARM_SPINX, PARM_SPINX, 0.0 )
				self.addChannel( IPARM_SPINY, PARM_SPINY, 0.0 )
				self.addChannel( IPARM_SPINZ, PARM_SPINZ, 0.0 )
				self.addChannel( IPARM_SPINAX, PARM_SPINAX, 0.0 )
				self.addChannel( IPARM_SPINAY, PARM_SPINAY, 0.0 )
				self.addChannel( IPARM_SPINAZ, PARM_SPINAZ, 0.0 )
				self.addChannel( IPARM_SPINVAR, PARM_SPINVAR, 0.0 )
				# Grow
				self.addChannel( IPARM_GROWX, PARM_GROWX, 0.0 )
				self.addChannel( IPARM_GROWY, PARM_GROWY, 0.0 )
				self.addChannel( IPARM_GROWZ, PARM_GROWZ, 0.0 )
				self.addChannel( IPARM_GROWAX, PARM_GROWAX, 0.0 )
				self.addChannel( IPARM_GROWAY, PARM_GROWAY, 0.0 )
				self.addChannel( IPARM_GROWAZ, PARM_GROWAZ, 0.0 )
				self.addChannel( IPARM_GROWVAR, PARM_GROWVAR, 0.0 )
				for i in range(nParticles):
						self.addParticle(i)
				self.setShape(nShape)
				if isinstance(nShape, str):
						self.shape = SHAPE_CUSTOM
				else:
						self.shape = nShape
		def addParticle(self, n):
				particle = PwParticle(self, "Particle_%i" % n )
				particle.addControlToScales( self.system.name, self.iname, IPARM_PSCALE, IPARM_PXSCALE, IPARM_PYSCALE, IPARM_PZSCALE, 0.01 )
				particle.addControlToRots( self.system.name, self.iname, IPARM_PXROTATE, IPARM_PYROTATE, IPARM_PZROTATE, 1.0 )
				particle.addChannel( IPARM_XSCALEMOD, PARM_XSCALEMOD, 0.0, hidden=True )
				particle.addChannel( IPARM_YSCALEMOD, PARM_YSCALEMOD, 0.0, hidden=True )
				particle.addChannel( IPARM_ZSCALEMOD, PARM_ZSCALEMOD, 0.0, hidden=True )
				particle.addModifierToScales( self.system.name, particle.iname, IPARM_XSCALEMOD, IPARM_YSCALEMOD, IPARM_ZSCALEMOD, 1.0 )
				self.particles.append( particle )
		def numParticles(self):
				return len( self.particles )
		def setShape(self, shape):
				geompath = shape
				if shape == SHAPE_BALL:
						geompath = GEOM_BALL
				elif shape == SHAPE_TORUS:
						geompath = GEOM_TORUS
				elif shape == SHAPE_PILL:
						geompath = GEOM_PILL
				elif shape == SHAPE_SPRITE:
						geompath = GEOM_SPRITE
				elif shape == SHAPE_CONE:
						geompath = GEOM_CONE
				for p in self.particles:
						p.setGeometry(geompath)
		def killAll(self):
				for p in self.particles:
						p.kill()
		def keyAll(self):
				for p in self.particles:
						p.key()
		def unkeyAll(self, frame):
				for p in self.particles:
						p.unkey(frame)

class PwAttractor(PwPoserActor):
		def __init__(self, obj):
				PwPoserActor.__init__(self)
				self.source = obj
				self.strength = self.source.Parameter(PARM_ATTRACTION)
				self.range = self.source.Parameter(PARM_RANGE)
				self.falloff = self.source.Parameter(PARM_FALLOFF)
		def getOrigin(self):
				return PwPoint(self.source.WorldDisplacement())
		def getStrength(self):
				return self.strength.Value()
		def setStrength(self, v):
				self.strength.SetValue(v)
		def getRange(self):
				return self.range.Value() * 0.190
		def setRange(self, v):
				self.range.SetValue(v)
		def getFalloff(self):
				return self.falloff.Value()
		def setFalloff(self, v):
				self.falloff.SetValue(v)

class PwDeflector(PwPoserActor):
		def __init__(self, obj):
				PwPoserActor.__init__(self)
				self.source = obj
				self.dampening = self.source.Parameter(PARM_DAMPENING)
				self.scale = self.source.ParameterByCode(poser.kParmCodeASCALE)
		def getDampening(self):
				return self.dampening.Value()
		def setDampening(self, v):
				self.dampening.SetValue(v)
		def getSize(self):
				return self.scale.Value()
		def setSize(self, v):
				self.scale.SetValue(v)

def getSystems():
		systems = []
		for system in poser.Scene().Figures():
				if isParticleFigure(system):
						systems.append( buildSystemFrom(system) )
		return systems

def getEmitters():
		emitters = []
		for actor in poser.Scene().Actors():
				if isEmitter(actor):
						emitters.append( actor )
		return emitters

def getAttractors():
		attractors = []
		for actor in poser.Scene().Actors():
				if isAttractor(actor):
						attractors.append( PwAttractor(actor) )
		return attractors

def getDeflectors():
		deflectors = []
		for actor in poser.Scene().Actors():
				if isDeflector(actor):
						deflectors.append( PwDeflector(actor) )
		return deflectors

def isParticleFigure(figure):
		parm = figure.ParentActor().Parameter(PARM_TYPE)
		if parm:
				if parm.Value() == GROUP_TYPE or parm.Value() == SYSTEM_TYPE:
						return 1
		return 0

def isEmitter(actor):
		parm = actor.Parameter(PARM_TYPE)
		if parm:
				if parm.Value() == EMITTER_TYPE:
						return 1
		return 0

def isParticle(actor):
		parm = actor.Parameter(PARM_TYPE)
		if parm:
				if parm.Value() == PARTICLE_TYPE:
						return 1
		return 0

def isAttractor(actor):
		parm = actor.Parameter(PARM_TYPE)
		if parm:
				if parm.Value() == ATTRACTOR_TYPE:
						return 1
		return 0

def isDeflector(actor):
		parm = actor.Parameter(PARM_TYPE)
		if parm:
				if parm.Value() == DEFLECTOR_TYPE:
						return 1
		return 0

def debug():
		system = createSystem("Particle Figure", [("Cones", 60, SHAPE_CONE)])

if __name__ == '__main__':
		for system in getSystems():
				print system.Name()
